/*
 * @Author: 0x9DEFA478
 * @Date: 2025-06-22 17:58:01
 * @LastEditTime: 2025-09-22 23:45:39
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * 
 */
#include "./H_Path.hpp"
#include <sstream>
#include <stdexcept>


static inline bool IsChar(char c,const std::string& charList){
  for(std::size_t i=0,length=charList.length();i<length;i++){
    if(c==charList[i]){
      return true;
    }
  }
  return false;
}


namespace H{


  const Path Path::Empty;

  Path::Path(){
  }
  Path::~Path(){
  }


  Path::Path(const Path& path):path(path.path){}

  Path::Path(Path&& path):path(std::move(path.path)){}


  Path& Path::operator=(const Path& path){
    if(this==&path){
      return *this;
    }
    this->path=path.path;
    return *this;
  }
  
  Path& Path::operator=(Path&& path){
    if(this==&path){
      return *this;
    }
    this->path=std::move(path.path);
    return *this;
  }
  
  Path& Path::operator+=(const Path& path){
    for(auto& Item:path.path){
      this->path.emplace_back(Item);
    }
    this->path.shrink_to_fit();
    return *this;
  }
  
  Path Path::operator+(const Path& path)const{
    Path r;

    r.path=this->path;
    for(auto& Item:path.path){
      r.path.emplace_back(Item);
    }
    r.path.shrink_to_fit();
    return r;
  }
  
  int Path::compare(const Path& path)const{
    if(this==&path){
      return 0;
    }

    std::size_t mlength=this->path.size();
    std::size_t olength=path.path.size();
    std::size_t length=olength;
    if(length>mlength){
      length=mlength;
    }

    for(std::size_t i=0;i<length;i++){
      auto cmp=this->path[i].compare(path.path[i]);
      if(cmp<0){
        return -1;
      }
      if(cmp>0){
        return 1;
      }
    }

    if(mlength<olength){
      return -1;
    }
    if(mlength>olength){
      return 1;
    }
    return 0;
  }
  
  bool Path::IsParentOrEqual(const Path& path)const{
    if(this==&path){
      return true;
    }

    if(this->path.size()>path.path.size()){
      return false;
    }

    return std::equal(this->path.begin(),this->path.end(),path.path.begin());
  }

  bool Path::IsRelative()const{
    if(path.empty()){
      return true;
    }
    if(path[0].length()<=0){// 根目录 /
      return false;
    }
    if(path[0][path[0].size()-1]==':'){// Windows盘符 C:/xxx
      return false;
    }
    return true;
  }

  bool Path::IsSuffix(const std::string suffix,bool CaseInsensitive)const{
    if(suffix.length()<1){
      return true;
    }
    if(path.size()<1){
      return false;
    }

    auto& last=*path.rbegin();

    if(last.length()<suffix.length()){
      return false;
    }

    if(!CaseInsensitive){
      return 0==last.compare(last.length()-suffix.length(),suffix.length(),suffix);    
    }

    auto dl=last.length()-suffix.length();
    for(std::size_t i=0,length=suffix.length();i<length;i++){
      char c0=last[dl+i];
      char c1=suffix[i];
      if((c0>='A')&&(c0<='Z')){
        c0+='a'-'A';
      }
      if((c1>='A')&&(c1<='Z')){
        c1+='a'-'A';
      }
      if(c0!=c1){
        return false;
      }
    }

    return true;
  }


  std::string Path::String(const std::string& splitText,const std::string& local)const{
    std::stringstream ss;
    if(path.empty()){
      return local;
    }
    for(std::size_t i=0,length=path.size();i<length;i++){
      if(i>0){
        ss<<splitText;
      }
      ss<<path[i];
    }
    return ss.str();
  }

  std::string Path::Name()const{
    if(path.size()<1){
      return "";
    }
    return *path.rbegin();
  }

  Path Path::DiscardRelative(bool DiscardEmpty,const std::string& local,const std::string& parent)const{
    Path r;
    bool isRelative;

    if(path.empty()){
      return r;
    }
    
    isRelative=IsRelative();

    auto iterator=path.begin();
    
    if(!isRelative){//非相对路径直接跳到下一个
      r.path.emplace_back(*iterator);
      iterator++;
    }

    for(;iterator!=path.end();iterator++){
      auto& Item=*iterator;
      
      if(DiscardEmpty&&(Item.length()<1)){
        continue;
      }
      if(Item==local){
        continue;
      }
      if(Item==parent){
        if(isRelative){
          if((r.path.size()>0)&&(r.path[r.path.size()-1]!=parent)){
            r.path.pop_back();
          }else{
            r.path.emplace_back(Item);
          }
        }else{
          if(r.path.size()>1){
            r.path.pop_back();
          }else{
            throw std::invalid_argument("错误的路径, 无法查找上一级路径");
          }
        }
        continue;
      }
      r.path.emplace_back(Item);
    }
    return r;
  }

  Path Path::ToRelative()const{
    Path r;
    if(path.empty()){
      return r;
    }

    if(path[0].length()<=0){// 根目录 /
      auto rLen=path.size()-1;
      if(rLen<1){
        return r;
      }
      r.path.resize(rLen);
      for(std::size_t i=0;i<rLen;i++){
        r.path[i]=path[1+i];
      }
      return r;
    }

    r.path=path;
    if(path[0][path[0].size()-1]==':'){// Windows盘符 C:/xxx
      r.path[0]=std::string(path[0],0,path[0].size()-1);
    }

    return r;
  }


  void Path::construct(const char* path,const std::string& splitCharList){
    char c;
    std::stringstream ss;

    auto addName=[this,&ss]{
      this->path.emplace_back(ss.str());
      ss=std::stringstream();
    };

    while((c=*path)!='\0'){
      path++;

      if(IsChar(c,splitCharList)){
        addName();
        continue;
      }

      ss<<c;
    }

    auto ends=ss.str();
    if(ends.length()>0){
      this->path.emplace_back(ss.str());
    }

    this->path.shrink_to_fit();
  }

  
}

